#include "include/cLib.h"
#include "include/Stack.h"
#include "include/ClassStack.h"
// 两个相同头文件里面有相同类，需要用命名空间来区分 namespace；
#include "include/Stash.h"
#include "include/Pstash.h"
#include "include/StringStack.h"
#include "src/Inline.cc"
#include "src/Rectangle.cc"
#include "include/Tree.h"
#include "src/Instrument.cc"
#include "src/PetInstrument.cc"
#include "include/StackTemplate.h"
#include "include/OwneStack.h"
// #include "fibnacci.h"
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int function1(void);
int function2();
int function3(float);
void function4(void);
// void function5(......); 不定参数
void removeHat(char hat); // 递归
void f(int *p);
void f(int &r);
int globe;
void func();
void function5();
void tune(Instrument &i);
enum ShapeType
{
    circle,
    square,
    rectangle
};
#define P(A) cout << #A << ":" << A << endl;
int main(int argc, char *argv[])
{
#ifdef DEFINE_CONDITION
    cout << "hello world1" << endl;
#endif
    cout << "hello world" << endl;
    // function1();
    // function3(1.23);
    // function4();
    // 3.2.1
    // true //false
    // 3.2.2 if - else
    // 3.2.3 while
    // 3.2.4 do-while
    // 3.2.5 for
    // 3.2.6 break continue
    // 3.2.7 switch
    /*
    bool quit = false;
    while (quit == false)
    {
        cout << "Select a,b,c or q to quit：";
        char response;
        cin >> response;
        switch (response)
        {
        case 'a':
            cout << "you choose a" << endl;
            break;
        case 'b':
            cout << "you choose b" << endl;
            break;
        case 'c':
            cout << "you choose c" << endl;
            break;
        case 'q':
            quit = true;
            cout << "you stop" << endl;
            break;
        default:
            cout << " Please Use a,b,c or q to quit："<<endl;
            break;
        }
    }
    */
    // 3.2.8 goto语句 一般不使用，不学
    // 3.2.9 递归
    // removeHat('A');

    // 3.3.1 优先级（数学算术优先级）
    // 3.3.2 自增，自减

    // 3.4.1 基本内建类型 char(1字节) int float double
    // 3.4.2 bool类型，true （1) 和 false (0)
    // 3.4.3 说明符 long，shot ,signed ,unsigned

    // 3.4.4 指针
    // int a = 4;
    // int *b = &a;
    // cout << "a:" << a<<endl;
    // cout << "*b:" << *b << "b:" << b << "&a:" << &a <<endl;
    // cout << &b <<endl;

    // 3.4.5 修改外部引用 传指针
    // int x = 47;
    // cout << "x:" << x << endl;
    // f(&x);
    // cout << "x:" << x << endl;

    // 3.4.6 传引用(赋别名)
    // int x=47;
    // f(x);   //里面值修改，外部一样变化
    // cout << x <<endl;
    // 3.4.7 指针和引用作为修饰符
    // 3.5 作用域
    // 3.5.1 实时定义变量
    // 3.6 指定存储空间分配
    // 3.6.1 全局变量
    // cout << globe << endl;
    // func();
    // cout << globe << endl;
    // 3.6.2 局部变量 （寄存器变量 register “尽可能快的访问这个变量”）
    // 3.6.3 静态变量
    // 3.6.4 外部变量 extern 关键字，声明别的文件有这个变量
    // 3.6.5 常量 const 声明这个值不会改变
    // 3.6.6 volatile 变量
    // 3.7 运算符及其使用
    // 3.7.1 赋值 “=”
    // 3.7.2 数学运算符
    // 3.7.3 关系运算符 “<” ">" "<=" ">=" "==" "!="
    // 3.7.4 逻辑运算符 “&&” “||” "!"
    // 3.7.5 位运算符 “&” "|" "~"
    // 3.7.6 移位运算符 “<<” ">>"
    // 3.7.7 一元运算符 "!"
    // 3.7.8 三元运算符 "a>b?a:b"
    // int a = 4, b = 5;
    // int c = a > b ? a : b;
    // cout << "c: " << c << endl;
    // 3.7.9 逗号运算符
    // 3.7.11 转换运算符
    // int b =200;
    // unsigned long a=(unsigned long int)b;
    // cout << b <<endl;
    // cout << a <<endl;
    // cout << sizeof(b) << endl;
    // cout << sizeof(a) << endl;

    // 3.7.12 c++ 的显式转换
    // static_cast
    // const_cast
    // reinterpret_cast
    // dynamic_cast  //动态类型转换，15章介绍

    // 3.7.13 sizeof-独立运算符
    // 3.7.14 asm 关键字  允许c++直接写汇编代码
    // 3.7.15 显式运算符
    // 例子：关键字 and  含义： &&（逻辑与）

    // 3.8 创建复合类型
    // 3.8.1 用typedef命名别名
    // typedef int* Intptr;
    // Intptr x, y;
    // int a = 12, b = 13;
    // x = &a, y = &b;
    // cout << *x << *y << endl;

    // 3.8.2 用struct把变量结合一起
    // 3.8.3 用enmu（枚举）提高程序清晰度
    // ShapeType shape = circle;
    // switch (shape)
    // {
    // case circle:
    //     cout << "circle" << endl;
    //     break;
    // case rectangle:
    //     cout << "rectangle" << endl;
    //     break;
    // case square:
    //     cout << " square" << endl;
    //     break;
    // default:
    //     break;
    // }

    // 3.8.4 用union节省内存（遇到再看？）review
    // 3.8.5 数组
    // typedef struct
    // {
    //     int i, j, k;
    // } Dpoint;

    // Dpoint p[10];
    // for (int i = 0; i < 10; i++)
    // {
    //     p[i].i = i + 1;
    //     p[i].j = i + 2;
    //     p[i].k = i + 3;
    // }
    // for (int i = 0; i < 10; i++)
    // {
    //     cout << p[i].i << endl;
    //     cout << p[i].j << endl;
    //     cout << p[i].k << endl;
    // }
    // 3.8.5.1 指针和数组
    // 3.8.5.2 探究浮点格式 float相关
    // 3.8.5.3 指针算术
    // int a[5] ={0,1,2,3,4};
    // int *p =&a[0];
    // for(int i =0;i<5;i++,p++){
    //     cout << *p << endl;
    // }

    // 3.9 调试技巧
    // 3.9.1 调试标记
    // 预处理器调试标记，运行期调试标记
    // #define DEBUG
    // #ifdef DEBUG
    // #endif
    // bool debug

    // 3.9.2 把变量和表达式转换成字符串
    // 标准c具有字符串化运算符”#“。在一个预处理器宏中，
    // 预处理器会把这个参数转换为一个字符数组
    // int a=1,b=2,c=3;
    // P(a);P(b);P(c);
    // P(a+b);

    // 3.10 函数地址
    // 3.10.1 定义函数指针
    // 3.10.2 复杂的声明和定义（遇到再看）？
    // 3.10.3 使用函数指针
    // void (*fp)();
    // fp =function5;
    // (*fp)();
    // void (*fp2)() = function5;
    // (*fp2)();
    // 3.10.4 指向函数的指针数组 （遇到再看）？

    // 4.1.1 动态存储分配
    //  CStash intStash;
    //  intStash.init(sizeof(int));
    //  for(int i=0;i<100;i++){
    //     intStash.add(&i);
    //  }
    //  for(int i=0;i<intStash.count();i++){
    //    cout << *(int *)intStash.fetch(i)<<endl;
    //  }

    // CStash stringStash;
    // char *cp;
    // ifstream in;
    // string line;
    // const int bufsize = 80;
    // stringStash.init(sizeof(char) * bufsize);
    // in.open("/Users/hello/Desktop/c++code/c-practice/main.cpp");
    // while (getline(in, line)){
    //     stringStash.add(line.c_str());
    // }
    // int i = 0;
    // //c++ 有严格的类型检查，它不允许直接向其他类型赋void*（c允许）
    // while ((cp = (char *)stringStash.fetch(i++)) != 0)
    // {
    //     cout << cp << endl;
    // }
    // 4.8 嵌套结构
    // Stack textLine;
    // string line;
    // ifstream in;
    // textLine.init();
    // in.open("/Users/hello/Desktop/c++code/c-practice/src/stack.cc");
    // while (getline(in,line))
    // {
    //     textLine.push(new string(line));
    // }
    // string * s;
    // while ((s=(string*)textLine.pop())!=0)
    // {
    //     cout << *s <<endl;
    //     delete s;
    // }
    // textLine.cleanup();

    // 4.8.1 全局作用域解析

    // 5 访问控制 private public protectd
    // 5.3 友元 friend关键字 ？
    // 5.5 类 class 默认权限private struct 默认权限 public
    // 5.6 句柄类 （c++的访问控制允许将实现部分和接口部分分开）
    // 5.6.1 隐藏实现
    // 5.6.2 减少重复编译

    // 6 初始化与清除
    // 6.1 构造函数保证初始化
    // 6.2 析构函数保证清除
    // 6.3 清除定义块 -- 尽量要使用时才定义变量，并初始化
    // 6.3.1 for循环
    //  for(int i=0;i<100;i++) c中不能直接这么定义
    // 6.3.2 内存分配
    // 6.4 带有构造函数和析构函数的Stash

    // char *cp;
    // ifstream in;
    // string line;
    // const int bufsize = 80;
    // Stash* stringStash =new Stash(sizeof(char) * bufsize);
    // // new Stash(sizeof(char) * bufsize) 返回的是指针
    // // Test test1;              栈中分配  ，由操作系统进行内存的分配和管理
    // // Test test2 = Test();     栈中分配  ，由操作系统进行内存的分配和管理
    // // Test *test3=new Test();  堆中分配  ，由管理者进行内存的分配和管理，用完必须delete()，否则可能造成内存泄漏
    // in.open("/Users/hello/Desktop/c++code/c-practice/main.cpp");
    // while (getline(in, line)){
    //     stringStash->add(line.c_str());
    // }
    // int i = 0;
    // while ((cp = (char *)stringStash->fetch(i++)) != 0)
    // {
    //     cout << cp << endl;
    // }
    // delete stringStash;

    // classStack::Stack* textLine =new classStack::Stack();
    // string line;
    // ifstream in;
    // in.open("/Users/hello/Desktop/c++code/c-practice/src/stack.cc");
    // while (getline(in,line))
    // {
    //     textLine->push(new string(line));
    // }
    // string * s;
    // while ((s=(string*)textLine->pop())!=0)
    // {
    //     cout << *s <<endl;
    //     delete s;
    // }

    // 6.6 聚合初始化
    //  数组
    //  int a[5] ={1,2,3,4,5};
    //  int b[6] ={0};
    //  int c[] = {1,2,3,4};
    //  for (int i = 0; i < sizeof c/ sizeof *c; i++)
    //  {
    //      cout<< c[i] << endl;
    //  }

    // 多构造函数
    // 6.7 默认构造函数
    // 默认构造函数是不带任何参数的构造函数。
    // 当且仅当一个结构中没有构造函数时，编译器会自动为它创建一个

    // 7 函数重载和默认参数
    // 7.1.1 c++不能返回值重载
    // 7.1.2 类型安全链接
    // void f(char);  int main(){f(1)}
    // c中能链接成功，c++不行，因为编译器会修饰方法名为类似f_int

    // char *cp;
    // ifstream in;
    // string line;
    // const int bufsize = 80;
    // Stash* stringStash =new Stash(sizeof(char) * bufsize,100);
    // in.open("/Users/hello/Desktop/c++code/c-practice/main.cpp");
    // while (getline(in, line)){
    //     stringStash->add(line.c_str());
    // }
    // int i = 0;
    // while ((cp = (char *)stringStash->fetch(i++)) != 0)
    // {
    //     cout << cp << endl;
    // }
    // delete stringStash;

    // 7.3 联合
    //  union与class的唯一不同之处在于存储数据的方式（在union中 int类型的数据和float类型的数据在内存区覆盖存放），
    //  但是union不能在继承的时候作为基类使用

    // 7.4 默认参数
    //  Stash(int size);
    //  Stash(int size,int initQuantity);
    //  合并Stash(int size,int initQuantity=0);

    // 7.4.1 占位符参数
    // void f(int x,int,float flt);  //中间参数没有标识符起到占位的目的

    // 7.5 选择重载还是默认参数
    // 需要中和效率和接口易读性来考虑

    // 8 常量
    // 关键字：const来表示，为了使程序员在变与不变之间画一条界线

    // 8.1 值替代
    // C 语言中用值替代名字典型用法
    // #define BUFSIZE 100
    // c++ 实现
    // const int bufsize = 100;
    // 8.1.1 头文件里的const
    // 要使用const，同样必须把const定义放进头文件里面
    // 必须赋值，否则需要用extern来声明
    // const 为内部连接一般就本cpp单元可见
    // 8.1.2 const 的安全性
    // 如果知道一个值是不可变的，使用const 修饰
    // 8.1.3 聚合
    // const 意味着 “不能改变的一块存储空间” ，不能在编译期间使用它值
    // const int i[]={1,2,3,4,5};
    // float f[i[3]] ={1.1,1.2,1.3}; 非法 ？

    // 8.2 指针
    // 8.2.1 指向const的指针
    //  int d=1;
    //  int e=2;
    //  const int* u =&d;
    //  // *u = 5; 非法
    //  cout << *u <<endl;
    //  u=&e; //合法
    //  cout << *u <<endl;
    //  // 指向的值不能被改变，但指向可以改变
    //  //8.2.2 const指针
    //  int* const v =&d;
    //  cout << *v <<endl;
    //  *v=3;//合法
    //  //v=&e;非法
    //  cout << *v <<endl;
    //  cout << d <<endl;
    //  指向不能改变 ，但指向的值可以改变
    // const int* const v;
    //  指向和指向的值都不能改变

    // 8.3 函数参数与返回值
    // 8.3.1 传递const值
    // 如果函数参数是按值传递，则可用指定参数是const
    // 例子
    //  void f1(const int i){
    //     // i++;//非法
    //  }

    // 8.3.2 返回const值
    // 8.3.3 传递和返回地址
    //  方法传地址和传引用通过声明const禁止修改指针或引用
    //  对于一些只写的场景
    //  void f(const int* clip);
    //  void f1(const int& clip1)

    // 8.4 类
    // 8.4.1 类里的const
    // 8.4.1.1 构造函数初始化列表->ConstInitialization.cc
    // 8.4.1.2 内建函数 的构造函数 -> built.cc

    // 8.4.2 编译期间类的常量
    //"关键字static 意味着不管类的对象被创建多少次，都只有一个实例，存放在内存的静态变量区"
    //  string helloword[] ={
    //      "hello world",
    //      "hello world1",
    //      "hello world2",
    //      "hello world3",
    //  };
    //  const int iCsz = sizeof helloword / sizeof *helloword;
    //  StringStack* ss = new StringStack();
    //  for(int i=0;i<iCsz;i++){
    //   ss->push(&helloword[i]);
    //  }
    //  const string* cp;
    //  while((cp=ss->pop())!=0){
    //    cout<<*cp <<endl;
    //  }
    //  delete ss;

    // 8.4.3 const 对象和成员函数 ？
    // 8.5 volatile 关键字 多线程相关 ？ c-v限定符

    // 9 内联函数
    // 9.2 内联函数 在c++中宏的概念是作为内联函数来实现的。
    // 内联函数在适当的地方像宏一样展开，所以不需要函数调用的开销
    // 1.任何在类中定义的函数自动地成为内联函数
    // 2.可以在非类的函数前面加上inline关键字使其成为内联函数
    // 3.函数体和声明必须在一起

    // 9.2.1 类内部的内联函数
    //  Point p, q(1,2,3);
    //  p.print("value for p");
    //  q.print("value for q");

    // 9.2.2 访问函数
    //  Access A;
    //  A.set(100);
    //  int x=A.read();

    // 9.2.2.1 访问器和修改器
    //  Rectangle r(19,47);
    //  r.height(2*r.height());
    //  r.width(2*r.width());
    //  cout << r.height() <<endl;
    //  cout << r.width() <<endl;
    //  cout << r <<endl;  //友元+重载运算符

    // 9.3 带内联函数的Stash和Stack
    // 可以将一些小函数作为内联函数，提供库出去怎么处理这些内联函数，暴露给其他人？

    // 9.4 内联函数与编译器
    // 9.4.1 限制
    //  有两种编译器不能执行内联的情况
    // 1. 函数太复杂
    // 2. 显式或隐式地取函数地址

    // 9.4.2 向前引用
    // Forword.cc

    // 9.4.3 在构造函数和析构函数里隐藏行为
    // src/Hidden.cc

    // 9.5 减少混乱
    //  newRectangle.cc
    // 9.6 预处理器的更多特征
    // 9.6.1 标志粘贴 标志粘贴 直接用“##”实现，它允许设两个标识符并把它们粘贴在一起并自动产生一个标识符？

    // 10 名字控制
    // 10.1 来自c语言中的静态元素
    //  c和c++，static都有两种基本含义
    //  1.在固定的地址上进行存储分配，也就是说对象是在一个特殊的静态数据区上创建的
    //  2.对一个特定的编译单位来说是局部的

    // 10.1.1 函数内部的静态变量
    // StaticInfunction.cc

    // 10.1.1.1 函数内部的静态对象
    // StaticInfunction.cc
    // 10.1.1.2 静态对象的析构函数
    //  静态对象的析构函数在程序从main()中退出时，或者标准的c库函数exit()被调用时才被调用。

    // 10.1.2 控制连接
    // 10.1.2.1 冲突问题
    // static的反义是extern
    // static 局部可见 extern 全局可见，这两者都是存在静态数据区

    // 10.1.3 其他存储类型说明符
    //  static，extern 比较常用
    //  auto（声明为局部变量，正常编译器能够通过上下文推断 比较少用
    //  c++ 11 新特性用于类型推导
    //  register（编译器优化比我们好） 比较少用

    // 10.2 名字空间
    // 10.2.1 创建一个名字空间
    //  namespace myLib{
    //  }

    // 10.2.1.1 未命名的的名字空间
    //  namespace {
    //       }

    // 10.2.1.2 友元
    // 可以在名字空间的类定义之内插入一个友元声明
    //  namespace Me{
    //      class Us
    //      {
    //          friend void you();
    //      }
    //  } 这样函数you()就成了名字空间Me的一个成员。

    // 使用命名空间
    // 两种形式 1 -> classStack.cc 2. stack.cc
    // 10.2.3 名字空间的使用

    // 10.3 c++中的静态成员
    // 10.3.1 定义静态数据成员的存储
    // 如果一个静态数据成员被声明但没有定义时，连接器会报告一个错误
    // staticInit.cc

    // 10.3.1.1 静态数组的初始化 ？

    // 10.3.2嵌套类和局部类
    // Local.cc

    // 10.3.3 静态成员函数
    // staticInit.cc
    // 类的设计者是想把这些函数与整个类在概念上关联起来。
    // 静态成员函数不能访问一般的数据成员，只能访问静态数据成员

    // 10.4 静态初始化的相依性 ？
    // 10.5 替代连接说明
    //  extern "C" float f(int a,int b); 重载extern 关键字实现
    //  告诉编译器 f() 是c 连接，这样就不会转换函数名

    // 11 引用和拷贝构造函数
    //  11.1 c++ 中的指针
    // c 不允许随便地把一个类型的指针赋值给另一个类型，但允许通过void*实现
    // c++ 则需要显性地使用类型转换

    // 11.2 c++中的引用
    // 使用引用规则
    // 1. 引用被创建时，必须被初始化
    // 2. 一旦一个引用被初始化为指向一个对象，它就不能改变为另一个对象的引用
    // 3. 不可能有NULL引用。

    // 11.2.1.1 常量引用
    //  void g(const int&){}

    // 11.2.1.2 指针引用
    // ReferenceToPointer.cc

    // 11.2.2 参数传递原则
    // 11.3 拷贝构造函数
    // HowMany.cc ,位拷贝？
    // 11.3.3 默认拷贝构造函数
    // Withcc.cc
    // 11.3.4 替代拷贝构造函数的方法
    //  11.3.4.1 防止按值传递
    //  11.3.4.2 改变外部对象的函数

    // 11.4 指向成员的指针
    // 11.4.1 函数（函数指针）（遇到再回来看）？
    // Pointer.cc

    // 12 运算符重载，这章了解这样即可（剩下遇到问题百度查找）
    // 12.2 定义重载的运算符就像定义函数，只是该函数的名字是operator@
    // src/OperatorOverloading.cc

    // 13 动态对象创建
    // 13.1.2 operator new
    //  创建一个对象所需的动作都结合在一个 “new” 运算符里，
    // 当用new 创建一个对象时，  它就在堆里为对象分配内存并为这块内存调用构造函数。
    // 13.1.3 operator delete
    // delete 表达式首先调用析构函数，然后释放内存
    //  Tree* t=new Tree(40);
    //  cout<< t<<endl;
    //  delete t;

    // 13.2.1 使用delete void* 可能会出错
    // 它将不执行析构函数
    // 13.2.3 指针的Stash
    //  PStash intStash;
    //  for (int i = 0; i < 25; i++)
    //  {
    //      intStash.add(new int(i));
    //  }
    //  for (int j = 0; j < intStash.count(); j++)
    //      cout << *(int *)intStash[j] << endl;
    //  for (int k = 0; k < intStash.count(); k++)
    //      delete intStash.remove(k);

    // PStash stringStash;
    // ifstream in;
    // string line;
    // in.open("/Users/hello/Desktop/c++code/c-practice/main.cc");
    // while (getline(in, line)){
    //     stringStash.add(new string(line));
    // }
    // for(int u=0;u<stringStash.count();u++)
    //    cout << *(string*) stringStash[u]<<endl;
    // for(int v=0;v<stringStash.count();v++)
    //    delete (string*) stringStash.remove(v);

    // 13.3 用于数组的new 和delete
    // MyType* fp=new MyType[100];
    // delete []fp;

    // 13.4 耗尽内存
    //  operator new() 找不到足够大的连续内存块来安排对象时，一个new-handler的特殊函数将会被调用

    // 13.5 重载new 和delete （该部分用到比较少 不学，遇到具体场景再百度？）
    // 分为类局部重载，全局重载

    // 14.继承和组合
    // 14.1 组合语法，在单类中使用其他类的方法，称为组合
    // class Y{
    //  X x;
    //  }
    // 14.2 继承语法
    // class Y:class X{
    //  }

    // 14.3 构造函数的初始化列表
    // 14.3.1 成员对象初始化
    // MyType2::MyType2(int i):Bar(i),m(i+1)
    // 14.3.2 在初始化表达式表中的内建类型

    // 14.4 组合和继承的联合
    // 组合和继承一起使用
    // 14.4.1 构造函数和析构函数调用的次序
    // Order.cc

    // 14.5 名字隐藏
    // 1.基类成员函数是虚函数，派生类实现该函数，称为重写
    // 2.基类成员函数，派生类重新实现该函数，称为重定义
    //  NameHiding

    // 14.6 非自动继承的函数
    // 不能被自动继承的方法：构造函数，析构函数，operator=

    // 14.6.1 继承和静态成员函数
    // 静态成员函数与非静态成员函数的共同点
    // 1.它们均可被继承到派生类中
    // 2.如果我们重新定义了一个静态成员，所有在基类中的其他重载函数会被隐藏
    // 3.如果我们改变了基类中一个函数的特征，所有使用该函数名字的基类版本都将会被隐藏

    // private继承
    // portected继承 与java类似

    // 14.9 运算符的重载与继承
    // 除了赋值运算符以外，其余的运算符可以自动地继承到派生类中

    // 14.10 多重继承
    // 14.11 渐增式开发
    // 14.12 向上类型转换

    // 15.0 多态性与虚函数
    //  Wind flute;
    //  tune(flute);
    // 没有加virture关键字，继承会以基类方法为准

    // 15.5c++如何实现晚捆绑
    // 通过创建虚函数来告诉编译器实现晚捆绑
    // 1.典型的编译器对每个包含虚函数的类创建一个表，虚函数表
    // 2.编译器带有虚函数的类中放了一个指针，指向虚函数表
    // 3.调用多态代码时，编译器静态的取得这个指针，并在虚函数表中查找函数地址的代码。

    // 15.6为什么需要虚函数，oop 实现程序员编程效率，但是会影响程序运行效率，需要衡量得失

    // 15.7抽象基类和纯虚函数
    // 纯虚函数的函数声明语法：
    //  virtual void f() = 0;
    // Wind flute;
    // Percussion per;
    // Brass brass;
    // Woodwind woodwind;
    // tune(flute);
    // tune(per);
    // tune(brass);
    // tune(woodwind);

    // 15.7.1 纯虚定义
    // 1.不允许产生抽象基类的对象
    // 2.希望一些公共代码，使一些或所有派生类定义都能调用
    // 例子：PetInstrument.cc
    Dog simba;
    simba.speak();
    simba.eat();

    // 15.8.1 对象切片 ？
    // 15.9 重载重定义
    // NameHiding.cc

    // 15.10 虚函数与构造函数
    // 15.10.1构造函数调用次序，所有基类构造函数总是在继承类构造函数中被调用。
    // 15.11 析构函数和虚拟析构函数
    // 构造函数是不能为虚函数的。但析构函数能够且常常必须是虚的，析构时已经知道对象类型了，构造时还不清楚。
    // 15.12 运算符重载 //
    // 15.13 向下类型转换
    // Pet *b = new Cat;
    // Dog *d1 = dynamic_cast<Dog *>(b);
    // Cat *d2 = dynamic_cast<Cat *>(b);
    // cout << "d1" << (long)d1 << endl; //不正确的向下类型转换返回了值0
    // cout << "d2" << (long)d2 << endl;

    // Rtti机制。运行时类型识别。

    // 16.3 模版语法
    // 16.3.1.1 头文件
    // 几乎总是在头文件放置全部的模版声明和定义。
    // 特殊情况下：（强制模版实例仅存在于单个的Windowsdll文件中）而要在一个独立的cpp文件中放置模版的定义

    StackTemplate<int> is;
    for (int i = 0; i < 20; i++)
        is.push(i);
    for (int i = 0; i < 20; i++)
        cout << is.pop() << endl;

    //16.3.3 模版中的常量
    //延迟初始化，不在构造函数初始化，而在第一次访问时初始化，例子：
    //Array3.CC    
   
    //16.5 打开和关闭所有权
    //创建和销毁对象所有权 src/OwnerStack.h

    return 0;
}
void tune(Instrument &i)
{
    i.play(middle);
}
void func()
{
    globe = 12;
}

void f(int *p)
{
    cout << "*p:" << *p << endl;
    *p = 5;
}

void f(int &r)
{
    cout << "r:" << r << endl;
    r = 46;
}

int function1(void)
{
    cout << "function1" << endl;
    return 0;
};
int function3(float)
{
    cout << "function3" << endl;
    return 0;
};
void function4(void)
{
    cout << "function4" << endl;
};
void function5()
{
    cout << "function5 be called" << endl;
};
void removeHat(char hat)
{
    if (hat <= 'Z')
    {
        cout << "hat: " << hat << endl;
        removeHat(hat + 1);
    }
    else
    {
        cout << "over" << endl;
    }
};